package tpcServer;

import java.io.BufferedReader;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.ByteBuffer;

import protocol.Protocol;
import outboxHandler.OutboxHandler;

import tokenizer.StringMessage;

/**############################################################################**/
class ConnectionHandlerTPC implements Runnable, OutboxHandler {
	
	private BufferedReader in;
	private PrintWriter out;
	private Socket clientSocket;
	private Protocol<StringMessage> protocol;
	protected ByteBuffer outbox;
	
	public ConnectionHandlerTPC(Socket acceptedSocket, Protocol<StringMessage> p)
	{
		in = null;
		out = null;
		clientSocket = acceptedSocket;
		protocol = p;
		/**############################################################################**/
		protocol.register(this);
		outbox=null;
		System.out.println("Accepted connection from client!");
		System.out.println("The client is from: " + acceptedSocket.getInetAddress() + ":" + acceptedSocket.getPort());
	}
	
	public void run()
	{	
		try {
			initialize();
		}
		catch (IOException e) {
			System.out.println("Error in initializing I/O");
		}
		
		//welcome message
		String welcomeMessage="Welcome to MiNiIRC, running version 1.0\n";
		updateOutBox(ByteBuffer.wrap(welcomeMessage.getBytes()));
		
		try {
			process();
		} 
		catch (IOException e) {
			System.out.println("Error in reading from I/O");
		}
		
		System.out.println("Connection closed - bye bye...");
		close();

	}
	
	/** ########################################################################## */	
	/**
	 * updating the outbox with messages for client
	 * @param outMessage - a vector containing the message to deliever to client
	 */
	public  synchronized void updateOutBox(ByteBuffer outMessage) {		//synch so each time only one client can update outbox to this client
		outbox=ByteBuffer.wrap(outMessage.array());
		write();
	}
	
	/** ########################################################################## */
	public synchronized void write() {			//synch so each time only one client can write to this client
		String s=new String(outbox.array());
		out.println(s);
	}
	
	public void process() throws IOException
	{
		String msg;
		
		while ((msg = in.readLine()) != null)
		{
			System.out.println("Received \"" + msg + "\" from client");
			/**###########################################################################**/
			protocol.processMessage(new StringMessage(msg));
			//String response = protocol.ParseMsg(msg);
			/*
			if (response != null)
			{
				out.println(response);
			}
			*/
			
			/**###########################################################################**/
			if (protocol.isEnd(new StringMessage(msg)))
			{
				break;
			}
			
		}
	}
	
	// Starts listening
	public void initialize() throws IOException
	{
		// Initialize I/O
		in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(),"UTF-8"));
		out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(),"UTF-8"), true);
		System.out.println("I/O initialized");
	}
	
	// Closes the connection
	public void close()
	{
		try {
			if (in != null)
			{
				in.close();
			}
			if (out != null)
			{
				out.close();
			}
			
			clientSocket.close();
		}
		catch (IOException e)
		{
			System.out.println("Exception in closing I/O");
		}
	}
	
}